home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Snippets / QuickDraw / Imageer 1.0.0d3 / Documentsƒ / ReadMe - Imageer 2⁄2 < prev    next >
Encoding:
Text File  |  1996-02-16  |  15.5 KB  |  248 lines  |  [ttro/ttxt]

  1. Imageer - Image processor
  2.  
  3. Written by: Jason Hodges-Harris,  Developer Technical Support.
  4.  
  5.  
  6. Interesting functions and how they operate
  7.  
  8. Color QuickDraw specific:
  9.  
  10. There are a few functions within this application which should  be of special interest. One of the which is the InvertColorTable() function included below. This is one example of how to safely manipulate a ColorTable , directly altering the values contained within each color entry.  
  11.  
  12. The theDocHndl structure passed into the function contains the handle to the window document structure which is to be edited. This is then accessed to determine the number of entries in the color table and the ColorTable Handle is locked down to avoid it moving in memory as the handle is dereferenced to a pointer for the loop operation to increase performance. After completion of the color amendments the CTabChanged() function is called for the ColorTable to notify that the structure had been altered. Finally the Handle is unlocked as its now safe to move in memory.
  13.  
  14.  
  15. OSErr InvertColorTable (ImageDocHndl    theDocHndl)
  16. {
  17.     CTabPtr        theColorTabPtr;
  18.     short            numberColors,
  19.                           count;
  20.     OSErr           error = noErr;
  21.     
  22.     numberColors = 1 << (*(*theDocHndl)->theImageWorld->portPixMap)->pixelSize;
  23.     HLock((Handle)(**(**theDocHndl).theImageWorld->portPixMap).pmTable);
  24.     theColorTabPtr = *(**(**theDocHndl).theImageWorld->portPixMap).pmTable;
  25.     for (count = 0;count < numberColors;count++)
  26.     {
  27.           theColorTabPtr->ctTable[count].rgb.red = 0xFFFF - theColorTabPtr->ctTable[count].rgb.red;
  28.           theColorTabPtr->ctTable[count].rgb.green = 0xFFFF - theColorTabPtr->ctTable[count].rgb.green;
  29.           theColorTabPtr->ctTable[count].rgb.blue = 0xFFFF - theColorTabPtr->ctTable[count].rgb.blue;
  30.     }
  31.   CTabChanged((**(**theDocHndl).theImageWorld->portPixMap).pmTable);
  32.   HUnlock((Handle)(**(**theDocHndl).theImageWorld->portPixMap).pmTable);
  33.   return error;
  34. }
  35.  
  36.  
  37. The other approach taken to manipulate color information was the use of a custom color search function. The following function implements a brightness control with a full range resolution of 32 steps. It takes the RGBColor value passed into the color search and adds a set value to each color component and limits the maximum color value to 0xFFFF.
  38.  
  39. pascal Boolean DirectColorBrightenProc(RGBColor *color,long *position)
  40. {
  41.     long    tempColorRed = color->red,
  42.             tempColorGreen = color->green,
  43.             tempColorBlue = color->blue;
  44.     
  45.     tempColorRed = (tempColorRed+0x1600) > 0xFFFF ? 0xFFFF : tempColorRed+0x1600;
  46.     tempColorGreen = (tempColorGreen+0x1600) > 0xFFFF ? 0xFFFF : tempColorGreen+0x1600;
  47.     tempColorBlue = (tempColorBlue+0x1600) > 0xFFFF ? 0xFFFF : tempColorBlue+0x1600;
  48.     color->red = tempColorRed;
  49.     color->green = tempColorGreen;
  50.     color->blue = tempColorBlue;
  51.     return false;
  52. }
  53.  
  54.  
  55. To call this function, a code block similar to the following can be used (this example is part of the ImageBrightness() function located in the imageFilter.c file):
  56.  
  57. ………
  58. theBrightnessColorSearchUPP = NewColorSearchProc(DirectColorBrightenProc); // create routine descriptor
  59. else
  60.    theBrightnessColorSearchUPP = NewColorSearchProc(DirectColorDarkenProc); // create routine descriptor
  61. AddSearch((ColorSearchUPP)theBrightnessColorSearchUPP);        // add color search
  62. CopyBits((BitMap*)(*thePixMapHndl),
  63.                         (BitMap*)(*thePixMapHndl),
  64.                         &(**theDocHndl).theImageWorld->portRect,
  65.                         &(**theDocHndl).theImageWorld->portRect,srcCopy,nil);
  66. DelSearch((ColorSearchUPP)theBrightnessColorSearchUPP);        // remove search
  67. DisposeRoutineDescriptor((UniversalProcPtr)theBrightnessColorSearchUPP);
  68. ………
  69.  
  70. Before using the custom color search function a routine descriptor has to be created for it to operate in native Power PC code. The UPP is then added to the GDevice's search list and by calling CopyBits() with both the source and destination ports set to the image port to be amended, alters the port's colors without requiring the allocation of more memory. All that is left is for the color search to be removed from the search list and the routine descriptor disposed as they're no longer required.
  71.  
  72.  
  73. The following section of code has been taken from the MirrorImageHorizontal() function and comprises of the loop used to read data from a directly from a locked Gworld PixMap into a pointer based buffer and from one part of the PixMap to another all using BlockMoveData() to avoid cache flushing (which can seriously reduce performance in Power PC code).
  74.  
  75. The in the example below the temporary storage buffer has been created, the PixMap locked down and the address mode set to 32 bits. The base address of the PixMap is then returned and the width of the PixMap in bytes, the mid Y axis value and the last line value are calculated. Then the loop processes the PixMap data from its original to its new  location  depending on  the image bit depth.
  76.  
  77. ………
  78. basePixMapAddr = imageLinePtr = GetPixBaseAddr(thePixMapHndl);    // base addr of image GWorld PixMap
  79. thePixMapRowBytes = (**thePixMapHndl).rowBytes & 0x3FFF;
  80. xSize = (**theDocHndl).theImageXSize;
  81. ySize = (**theDocHndl).theImageYSize;
  82. yMidValue = ySize * 0.5;
  83. destinationLine = ySize-1;
  84. for (yCount = 0;yCount<yMidValue;yCount++)
  85. {
  86.             BlockMoveData(imageLinePtr,lineBufferPtr,imageRowSize);    
  87.             switch ((**theDocHndl).theImageDepth)
  88.             {
  89.                 case 8:
  90.                         BlockMoveData(&basePixMapAddr[thePixMapRowBytes*destinationLine],imageLinePtr,imageRowSize);    
  91.                         BlockMoveData(lineBufferPtr,&basePixMapAddr[thePixMapRowBytes*destinationLine],imageRowSize);    
  92.                 break;
  93.                 case 16:
  94.                         BlockMoveData(&basePixMapAddr[thePixMapRowBytes*destinationLine],imageLinePtr,imageRowSize);    
  95.                         BlockMoveData(lineBufferPtr,&basePixMapAddr[thePixMapRowBytes*destinationLine],imageRowSize);    
  96.                 break;
  97.                 case 24:
  98.                 case 32:
  99.                         BlockMoveData(&basePixMapAddr[thePixMapRowBytes*destinationLine],imageLinePtr,imageRowSize);    
  100.                         BlockMoveData(lineBufferPtr,&basePixMapAddr[thePixMapRowBytes*destinationLine],imageRowSize);    
  101.                 break;
  102.             }
  103.             imageLinePtr += thePixMapRowBytes;
  104.             destinationLine--;
  105. }
  106. ………
  107.  
  108.  
  109. QuickDraw GX specific:
  110.  
  111. The following code block is used to convert Color QuickDraw commands to their nearest QuickDraw GX equivalents. By calling CopyBits() onto itself the translator function creates a gxBitmap shape containing the converted image data. The second routine below is the shape spooling function required by GXInstallQDTranslator() which is passed the translated objects. Even though the translation is not 100% accurate, as only PixMaps are converted from Color QuickDraw to QuickDraw GX, there is minimal/no difference between the two and therefore this technique is more than suitable.
  112.  
  113. ………
  114. theGXSpoolUPP = NewgxShapeSpoolProc(qdShapeSpooler);
  115. HLock((Handle)theDocHndl);
  116. GXInstallQDTranslator((GrafPtr)(*theDocHndl)->theImageWorld, gxDefaultOptionsTranslation,
  117.                  &(*theDocHndl)->theImageWorld->portRect,
  118.                  &(*theDocHndl)->theImageWorld->portRect,
  119.                     scale, theGXSpoolUPP, (void*)(*theDocHndl));
  120. SetGWorld((**theDocHndl).theImageWorld,nil);
  121. CopyBits((BitMap*)(*thePixMapHndl),
  122.                  (BitMap*)(*thePixMapHndl),
  123.                  &(**theDocHndl).theImageWorld->portRect,
  124.                  &(**theDocHndl).theImageWorld->portRect,srcCopy,nil);
  125. HUnlock((Handle)theDocHndl);
  126. GXRemoveQDTranslator((GrafPtr)(*theDocHndl)->theImageWorld,nil);
  127. DisposeRoutineDescriptor((UniversalProcPtr)theGXSpoolUPP);
  128. ………
  129.  
  130.  
  131. OSErr qdShapeSpooler (gxShape theShape, void *theDocHndlRef)
  132. {
  133.     ImageDocPtr theDocPtr = (ImageDocPtr)theDocHndlRef;
  134.     
  135.     theDocPtr->theGXImageShape = GXCopyToShape(nil, theShape);
  136.     GXSetShapeViewPorts(theDocPtr->theGXImageShape,1,&(theDocPtr->theGxChildView));
  137.     GXDisposeShape(theShape);
  138.     return    (GXGetGraphicsError(nil));
  139. }
  140.  
  141.  
  142. As the is no function within QuickDraw GX to directly support a mirror image transformation, the following code block taken from the MirrorGxShape() function, shows how such an operation can be created by the manipulation of a gxShape's  transformation matrix.
  143.  
  144. To determine which axis is to be altered, a  boolean is passed as a parameter in the function.
  145. First the transformation structure of the gxShape is  returned and elements of the matrix are reset to their identity values with the exception of the values stored in location [0][0] and [1][1], as these control the mirror transformation.
  146. By setting the [0][0] to ff(-1) and location [1][1] to ff(1), the image is mirrored along the Y axis and the other valid setting is [0][0] to ff(1) and [1][1] to ff(-1). Note also that setting both of these value to ff(1) produces and identity transformation and both to ff(-1) will negate the pixel locations effectively mirroring the image in the line x = 0. The other setting of ff(0) produces 0 results and therefore is of little normal use. Then set the amended transformation matrix to the gxShape and notify that the gxShape's transformation has altered. 
  147.  
  148. ………
  149. theShapeTransform = GXGetShapeTransform((**theDocHndl).theGXImageShape);
  150. GXGetShapeCenter((**theDocHndl).theGXImageShape,0,&theImageCentre);
  151.  
  152. /****    Identity transform matrix elements    ****/
  153. theTransMapping.map[1][0] = 0;
  154. theTransMapping.map[2][0] = 0;
  155. theTransMapping.map[0][1] = 0;
  156. theTransMapping.map[2][1] = 0;
  157. theTransMapping.map[0][2] = 0;
  158. theTransMapping.map[1][2] = 0;
  159. theTransMapping.map[2][2] = fract1;
  160. if (isXaxis)        // mirror shape along X axis
  161. {
  162.         theTransMapping.map[0][0] = ff(1);
  163.         theTransMapping.map[1][1] = ff(-1);
  164. }
  165. else                // mirror shape along Y axis
  166. {
  167.         theTransMapping.map[0][0] = ff(-1);
  168.         theTransMapping.map[1][1] = ff(1);
  169. }
  170. GXMapTransform(theShapeTransform,&theTransMapping);
  171. GXSetShapeTransform((**theDocHndl).theGXImageShape, theShapeTransform);
  172. GXSetShapeAttributes((**theDocHndl).theGXImageShape, gxMapTransformShape);
  173. GXGetShapeBounds((**theDocHndl).theGXImageShape, 0, &theShapeBounds);
  174. if (isXaxis)
  175.         GXMoveShape((**theDocHndl).theGXImageShape,0, theShapeBounds.bottom - theShapeBounds.top);
  176. else
  177.         GXMoveShape((**theDocHndl).theGXImageShape,theShapeBounds.right - theShapeBounds.left, 0);    
  178. GXSetShapeAttributes((**theDocHndl).theGXImageShape, gxNoAttributes);
  179. SetGWorld((CGrafPtr)theWindow,theGDevHndl);
  180. InvalRect(&theWindow->portRect);        // invalidate window port rect
  181. SetGWorld(oldPort,theGDevHndl);
  182. …………
  183.  
  184. General application:
  185.  
  186. As there can be multiple document windows open and each can either contain Color QuickDraw or QuickDraw GX image data, as well as the status window containing the windows color information, the following code block outlines how the problem of handling the update events was solved.
  187.  
  188. The code below is the main section of the DoWindowUpdate() function and after starting the update process retrieves the refcon value for the window to be updated. This value contains the handle to the window document structure and by checking values stored in this structure determines what the type of window requiring the update is and therefore calls the correct redraw function.
  189.  
  190. ………
  191. BeginUpdate(theWindow);            // start update process
  192. theWindDocHndl = (ImageDocHndl)GetWRefCon(theWindow);
  193. if (theWindDocHndl && (**theWindDocHndl).isColorsWindow == false && 
  194.                           (**theWindDocHndl).isUsingQDGX == false)
  195. {
  196.    TransferImageToWindow(theWindDocHndl,theWindow);    // Color QD content region update
  197.         UpdateControls(theWindow,theWindow->visRgn);
  198.    DrawGrowIcon(theWindow);
  199. }
  200. else if (theWindDocHndl && 
  201.                 (**theWindDocHndl).isColorsWindow == false && 
  202.                 (**theWindDocHndl).isUsingQDGX)
  203.    {
  204.       UpdateGXObjectDisplay(theWindDocHndl, theWindow);
  205.           UpdateControls(theWindow,theWindow->visRgn);
  206.           DrawGrowIcon(theWindow);
  207.    }
  208.    else if ((**theWindDocHndl).isColorsWindow && 
  209.                (**theWindDocHndl).isUsingQDGX == false)
  210.       DrawImageColors(theWindow);
  211. EndUpdate(theWindow);            // end update process
  212. ………
  213.  
  214. Known limitations and bugs:
  215.  
  216. •   In the initial release version there was a nasty intermittent bug   when converting a Color QuickDraw based image to 
  217. a QuickDraw GX shape. This was tracked down to the spool routine disposing of the gxShape passed into the routine and the gxShape being disposed of a second time from inside the GXInstallQDTranslator() function. As the spool routine was closely based on the listing 1-6 on page 1-22 of Inside Macintosh QuickDraw GX "Environment and Utilities", it appears that this listing is in error and the GXDisposeShape() call in the spool routine should not be used.
  218.  
  219. •   If the application is built with either Think C 7.0.x or the 68k version of CodeWarrior and it is compiled and linked with 2 byte ints, then certain of the effects functions can crash the machine. This is currently being tracked down and will be fixed in a future release. In the short term if the application is built using 4 byte ints, this problem doesn't occur.
  220.  
  221. •   When a QuickTime compressed PICT is loaded, as the depth of the GWorld is reliant on the information returned by GetPictInfo(), this causes only a value of 1 to be returned as GetPictInfo() isn't aware of the new QuickTime image PICT opcodes. The result is that the loaded image is stored as a dithered black and white image. As this problem is known about, a solution has already been planned and is high on the agenda for fixing in the next release.
  222.  
  223. •   The "Show Image Colors" window doesn't update correctly when the active image windows are switched and they contain images of different bit depths. 
  224.  
  225. •   The correct "Model", either QuickDraw GX or Color QuickDraw, must be selected before saving an image. If the incorrect model is in use, the image will not be saved.
  226.  
  227.  
  228. Further enhancements and improvements.
  229.  
  230. I hope that this application has provided some useful information regarding the parsing of foreign image file formats, the manual creation of color tables, writing directly into a GWorld, QuickDraw GX transform manipulations and how its possible to integrate both Color QuickDraw and QuickDraw GX into a single application. Also if you're thinking about QuickDraw GX, it should provide a starting point for your own experiments and i've also listed below a few pointers where improvements and enhancements could be made and are currently under consideration for future versions..
  231.  
  232. •   Support for active scrolling of the contents of the image windows, including updating the window contents when dragging a scroll bar thumb control. This has been left out of the current release as certain GX based operations can be slow to redraw. Therefore,  redrawing take place only after the mouse button has been released.
  233.  
  234.  •   Support for drag and drop between windows including the conversion between both imaging technologies (this could be only one way) and the ability to drag the image to the window to create new file via HFSflavor drag operation.
  235.  
  236. •   Greater support for the TIFF file format including compression and the ability to save the file in this format with both compression (optional) and in either PC or Mac byte order.
  237.  
  238. •   Altering the architecture of the application so that the filters and processing effects are based on components and during the initialization phase the application determines what functionality is available.
  239.  
  240. •   Full support for loading QuickDraw GX based image files. This is of high importance although time beat this feature being included in this release, expect to see its inclusion soon.
  241.  
  242. •   Menu handling to be improved so that only those items which are can be selected are enabled for use. e.g. if a menu item performs a different function dependent on the imaging model used or the current windows state, then this should be reflected in the state of the menu item.
  243.  
  244. •   Support for a method of conversion between QuickDraw GX to Color QuickDraw. Even though there is now the QuickTime codec which supports such a facility, it would be useful for example to convert directly between a gxBitmap Shape object to a PixMap including color information.
  245.  
  246.  
  247. Jason Hodges-Harris, December 1995.
  248. ©Apple Computer inc 1995. All rights reserved.